#pragma once
#include <vector>
#include <iostream>
#include <pthread.h>
#include "sem.hpp"

static int g_default_num = 5;

template <class T>
class RingQueue
{
public:
    RingQueue(int default_num = g_default_num)
        : _rq(default_num), _num(default_num), c_step(0), p_step(0), _space_sem(g_default_num), _data_sem(0)
    {
        pthread_mutex_init(&_clock, nullptr);
        pthread_mutex_init(&_plock, nullptr);
    }
    ~RingQueue() 
    {
        pthread_mutex_destroy(&_clock);
        pthread_mutex_destroy(&_plock);
    }

    void Push(const T &in)
    {
        _space_sem.p();
        pthread_mutex_lock(&_plock);
        _rq[p_step++] = in;
        p_step %= _num;
        pthread_mutex_unlock(&_plock);
        _data_sem.v();
    }

    void Pop(T *out)
    {
        _data_sem.p();
        pthread_mutex_lock(&_clock);
        *out = _rq[c_step++];
        c_step %= _num;
        pthread_mutex_unlock(&_clock);
        _space_sem.v();
    }

    void debug()
    {
        std::cout << "size: " << _rq.size() << " num: " << _num << std::endl;
    }

private:
    std::vector<T> _rq;
    int _num;
    int c_step; // 消费下标
    int p_step; // 生产下标
    Sem _space_sem;
    Sem _data_sem;
    
    pthread_mutex_t _clock;
    pthread_mutex_t _plock;
};